/*
 * @Date: 2019-12-2
 * @Author: xuechengwu <xuechengwu@erayt.com>
 * @Description: 指标层
 */
import BaseLayer from './BaseLayer';
import macd from '../quota/macd';
import kdj from '../quota/kdj';
import rsi from '../quota/rsi';
import cci from '../quota/cci';
import bias from '../quota/bias';
import ad from '../quota/ad';
import ma from '../quota/ma';
import arbr from '../quota/arbr';
import aroon from '../quota/aroon';
import atr from '../quota/atr';
import cmo from '../quota/cmo';
import cr from '../quota/cr';
import cv from '../quota/cv';
import dma from '../quota/dma';
import dmi from '../quota/dmi';
import dpo from '../quota/dpo';
import emv from '../quota/emv';
import forceIndex from '../quota/forceIndex';
import mfi from '../quota/mfi';
import mtm from '../quota/mtm';
import nvi from '../quota/nvi';
import obv from '../quota/obv';
import psy from '../quota/psy';
import pvi from '../quota/pvi';
import roc from '../quota/roc';
import rvi from '../quota/rvi';
import vr from '../quota/vr';
import vhf from '../quota/vhf';
import wad from '../quota/wad';
import wms from '../quota/wms';
import wvad from '../quota/wvad';
import MACDLayer from './MACDLayer';
import MultiLineLayer from './MultiLineLayer';
import SymmetryLayer from './SymmetryLayer';

function defaultQuoteCaculator(layer, data, start, end) {
  const funcs = {
    macd(layer, data, start, end) {
      const { DIFLen = 12, DEALen = 26, M = 9 } = layer.params;
      let maxParam = DIFLen;
      if (DEALen > maxParam) {
        maxParam = DEALen;
      }
      if (M > maxParam) {
        maxParam = M;
      }
      let dataStart = start - maxParam - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length - 1) {
        end = data.length - 1;
      }
      const close = [];
      for (let i = dataStart; i <= end; i++) {
        close.push(data[i].close);
      }
      const { DIF, DEA, BAR } = macd(close, DIFLen, DEALen, M);
      const dataLen = end - start + 1;
      const DIFData = [];
      const DEAData = [];
      const BARData = [];
      for (let i = DIF.length - dataLen; i < DIF.length; i++) {
        DIFData.push(DIF[i]);
        DEAData.push(DEA[i]);
        BARData.push(BAR[i]);
      }
      layer.quoteLayer = new MACDLayer(layer.canvas, {
        data: {
          DIF: DIFData,
          DEA: DEAData,
          BAR: BARData
        },
        xStep: layer.xStep,
        width: layer.width,
        height: layer.height,
        barRed: layer.barRedColor,
        barGreen: layer.barGreenColor,
        difColor: layer.difColor,
        deaColor: layer.deaColor
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = DIFData.length + shift;
        }
        return [{
          label: 'DIF',
          value: DIFData[shift]
        }, {
          label: 'DEA',
          value: DEAData[shift],
        }, {
          label: 'BAR',
          value: BARData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
     },
    kdj(layer, data, start, end) {
      const { N = 9, M = 3, L = 3, S = 3 } = layer.params;
      let dataStart = start - N - M - L -S - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length - 1) {
        end = data.length - 1;
      }
      let high = [];
      let low = [];
      let close = [];
      for (let i = dataStart; i <= end; i++) {
        high.push(data[i].high);
        low.push(data[i].low);
        close.push(data[i].close);
      }
      const { KValue, DValue, JValue } = kdj(high, low, close, N, M, L, S);
      const dataLen = end - start + 1;
      let KData = [];
      let DData = [];
      let JData = [];
      for (let i = KValue.length - dataLen; i < KValue.length; i++) {
        KData.push(KValue[i]);
        DData.push(DValue[i]);
        JData.push(JValue[i]);
      }
      layer.quoteLayer = new MultiLineLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: KData,
          color: layer.KColor || '#4587D9',
        }, {
          data: DData,
          color: layer.DColor || '#B345D9',
        }, {
          data: JData,
          color: layer.JData || '#F9B945'
        }],
        thresholds: [80, 50, 20],
        max: 100,
        min: 0,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = KData.length + shift;
        }
        return [{
          label: 'K',
          value: KData[shift],
        }, {
          label: 'D',
          value: DData[shift]
        }, {
          label: 'J',
          value: JData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    bias(layer, data, start, end) {
      const { N1 = 6, N2 = 10, N3 = 30 } = layer.params;
      let maxParam = N1;
      if (N2 > maxParam) {
        maxParam = N2;
      }
      if (N3 > maxParam) {
        maxParam = N3;
      }
      let dataStart = start - maxParam - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length - 1) {
        end = data.length - 1;
      }
      const close = [];
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
      }
      const biasN1 = bias(close, N1);
      const biasN2 = bias(close, N2);
      const biasN3 = bias(close, N3);
      const dataLen = end - start + 1;
      const biasN1Data = [];
      const biasN2Data = [];
      const biasN3Data = [];
      for (let i = biasN1.length - dataLen; i < biasN1.length; i++) {
        biasN1Data.push(biasN1[i]);
        biasN2Data.push(biasN2[i]);
        biasN3Data.push(biasN3[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        xStep: layer.xStep,
        base: 0,
        thresholds: [-16, -8, 8, 16],
        data: [{
          color: layer.BiasColor1 || '#4587D9',
          data: biasN1Data
        }, {
          color: layer.BiasColor2 || '#B345D9',
          data: biasN2Data
        }, {
          color: layer.BiasColor3 || '#F9B945',
          data: biasN3Data
        }],
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = biasN1Data.length + shift;
        }
        return [{
          label: `BIAS(${N1})`,
          value: biasN1Data[shift]
        }, {
          label: `BIAS(${N2})`,
          value: biasN2Data[shift]
        }, {
          label: `BIAS(${N3})`,
          value: biasN3Data[shift]
        }]
      });
      layer.addChild(layer.quoteLayer);
    },
    rsi(layer, data, start, end) {
      const { N1 = 12, N2 = 16, N3 = 24 } = layer.params;
      let maxParam = N1;
      if (N2 > maxParam) {
        maxParam = N2;
      }
      if (N3 > maxParam) {
        maxParam = N3;
      }
      let dataStart = start - maxParam - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length - 1) {
        end = data.length - 1;
      }
      let close = [];
      for (let i = dataStart; i <= end; i++) {
        close.push(data[i].close);
      }
      const rsiN1 = rsi(close, N1);
      const rsiN2 = rsi(close, N2);
      const rsiN3 = rsi(close, N3);
      let dataLen = end - start + 1;
      const rsiN1Data = [];
      const rsiN2Data = [];
      const rsiN3Data = [];
      for (let i = rsiN1.length - dataLen; i < rsiN1.length; i++) {
        rsiN1Data.push(rsiN1[i]);
        rsiN2Data.push(rsiN2[i]);
        rsiN3Data.push(rsiN3[i]);
      }
      layer.quoteLayer = new MultiLineLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        xStep: layer.xStep,
        data: [{
          data: rsiN1Data,
          color: layer.N1Color || '#4587D9'
        }, {
          data: rsiN2Data,
          color: layer.N2Color || '#B345D9',
        }, {
          data: rsiN3Data,
          color: layer.N3Color || '#F9B945'
        }],
        thresholds: [30, 50, 70],
        max: 100,
        min: 0,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = rsiN1Data.length + shift;
        }
        return [{
          label: `N${N1}`,
          value: rsiN1Data[shift]
        }, {
          label: `N${N2}`,
          value: rsiN2Data[shift],
        }, {
          label: `N${N3}`,
          value: rsiN3Data[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    cci(layer, data, start, end) {
      const { N = 24 } = layer.params;
      let dataStart = start - N - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length - 1) {
        end = data.length - 1;
      }
      const high = [];
      const low = [];
      const close = [];
      for (let i = dataStart; i < end; i++) {
        high.push(data[i].high);
        low.push(data[i].low);
        close.push(data[i].close);
      }
      const CCI = cci(high, low, close, N);

      let dataLen = end - start + 1;
      const cciData = [];
      for (let i = CCI.length - dataLen; i < CCI.length; i++) {
        cciData.push(CCI[i]);
      }
      console.log(CCI)
      console.log(cciData);
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
         data: cciData,
         color: layer.CCIColor || '#4587D9'
        }],
        thresholds: [-100, 100],
        base: 0,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = CCI.length + shift;
        }
        return [{
          label: 'CCI',
          value: CCI[shift]
        }]
      });
      layer.addChild(layer.quoteLayer);
    },
    ad(layer, data, start, end) {
      const { M = 6 } = layer.params;
      const high = [],
          low = [],
          close = [],
          volume = [];
      for (let i = 0; i < data.length; i++) {
        high.push(data[i].high);
        low.push(data[i].low);
        close.push(data[i].close);
        volume.push(data[i].volume);
      }
      const adv = ad(high, low, close, volume);

      if (end > data.length - 1) {
        end = data.length - 1;
      }
      let dataLen = end - start + 1;
      let adMa = ma(adv, M);
      let adData = [];
      let adMaData = [];
      for (let i = dataLen; i > 0; i--) {
        adData.push(adv[adv.length - i]);
        adMaData.push(adMa[adMa.length - i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data:adData,
          color: layer.ADColor || '#F5FF3D'
        }, {
          data: adMaData,
          color: layer.ADMAColor || '#FFFFFF'
        }],
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = adData.length + shift;
        }
        return [{
          label: 'AD',
          value: adData[shift],
        }, {
          label: `ADMA(${M})`,
          value: adMaData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    arbr(layer, data, start, end) {
      const { N = 26 } = layer.params;
      const high = [],
          low = [],
          close = [],
          open = [];
      let dataStart = start - N - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length - 1) {
        end = data.length - 1;
      }
      for (let i = dataStart; i < end; i++) {
        high.push(data[i].high);
        low.push(data[i].low);
        close.push(data[i].close);
        open.push(data[i].open);
      }
      const { ar, br } = arbr(open, high, low, close, N);
      let dataLen = end - start + 1;
      let arData = [],
          brData = [];
      for (let i = ar.length - dataLen; i < ar.length; i++) {
        arData.push(ar[i]);
        brData.push(br[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: arData,
          color: layer.ARColor || '#F44343'
        }, {
          data: brData,
          color: layer.BRColor || '#45F434'
        }],
        thresholds: [40, 100, 140, 180, 200],
        base: 100,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = arData.length + shift;
        }
        return [{
          label: 'AR',
          value: arData[shift]
        }, {
          label: 'BR',
          value: brData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    aroon(layer, data, start, end) {
      const { N = 20 } = layer.params;
      const high = [],
          low = [];
      let dataStart = start - N - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length - 1) {
        end = data.length - 1;
      }
      for (let i = dataStart; i < end; i++) {
        high.push(data[i].high);
        low.push(data[i].low);
      }
      const { uparoon, downaroon } = aroon(high, low, N);
      let dataLen = end - start + 1;
      let upData = [],
          downData = [];
      for (let i = uparoon.length - dataLen; i < uparoon.length; i++) {
        upData.push(uparoon[i]);
        downData.push(downaroon[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: upData,
          color: layer.UPAROONColor || '#F44343'
        }, {
          data: downData,
          color: layer.DOWNAROONColor || '#45F434'
        }],
        thresholds: [30, 70],
        base: 50,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = upData.length + shift;
        }
        return [{
          label: 'UPAROON',
          value: upData[shift]
        }, {
          label: 'DOWNAROON',
          value: downData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    atr(layer, data, start, end) {
      const { N = 14 } = layer.params;
      const high = [],
          close = [],
          low = [];
      let dataStart = start - N - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length - 1) {
        end = data.length - 1;
      }
      for (let i = dataStart; i < end; i++) {
        high.push(data[i].high);
        low.push(data[i].low);
        close.push(data[i].close);
      }
      const atrV = atr(high, low, close, N);
      let dataLen = end - start + 1;
      let atrData = [];
      for (let i = atrV.length - dataLen; i < atrV.length; i++) {
        atrData.push(atrV[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: atrData,
          color: layer.ATRColor || '#FFFFFF'
        }],
        thresholds: [],
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = atrData.length + shift;
        }
        return [{
          label: 'ATR',
          value: atrData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    cmo(layer, data, start, end) {
      const { N = 14 } = layer.params;
      const close = [];
      let dataStart = start - N - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length - 1) {
        end = data.length - 1;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
      }
      const cmoV = cmo(close, N);
      let dataLen = end - start + 1;
      let cmoData = [];
      for (let i = cmoV.length - dataLen; i < cmoV.length; i++) {
        cmoData.push(cmoV[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: cmoData,
          color: layer.CMOColor || '#FFFFFF'
        }],
        thresholds: [-50, 50],
        base: 0,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = cmoData.length + shift;
        }
        return [{
          label: `CMO(${N})`,
          value: cmoData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    cr(layer, data, start, end) {
      const { N = 14 } = layer.params;
      const close = [],
            high = [],
            low = [];
      let dataStart = start - N - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length - 1) {
        end = data.length - 1;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
        high.push(data[i].high);
        low.push(data[i].low);
      }
      const crV = cr(high, low, close, N);
      let dataLen = end - start + 1;
      let crData = [];
      for (let i = crV.length - dataLen; i < crV.length; i++) {
        crData.push(crV[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: crData,
          color: layer.CRColor || '#FFFFFF'
        }],
        thresholds: [40, 160],
        base: 100,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = crData.length + shift;
        }
        return [{
          label: `CR(${N})`,
          value: crData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    cv(layer, data, start, end) {
      const { N = 14 } = layer.params;
      const high = [],
          low = [];
      let dataStart = start - N - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length - 1) {
        end = data.length - 1;
      }
      for (let i = dataStart; i < end; i++) {
        high.push(data[i].high);
        low.push(data[i].low);
      }
      const cvV = cv(high, low, N);
      let dataLen = end - start + 1;
      let cvData = [];
      for (let i = cvV.length - dataLen; i < cvV.length; i++) {
        cvData.push(cvV[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: cvData,
          color: layer.CVColor || '#FFFFFF'
        }],
        thresholds: [30, 70],
        base: 50,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = cvData.length + shift;
        }
        return [{
          label: `CV(${N})`,
          value: cvData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    dma(layer, data, start, end) {
      const { fast = 6, slow = 12, smooth = 6 } = layer.params;
      const close = [];
      let dataStart = start - fast - slow - smooth - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length - 1) {
        end = data.length - 1;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
      }
      const { dmaValue, amaValue } = dma(close, fast, slow, smooth);
      let dataLen = end - start + 1;
      let dmaData = [],
          amaData = [];
      for (let i = dmaValue.length - dataLen; i < dmaValue.length; i++) {
        dmaData.push(dmaValue[i]);
        amaData.push(amaValue[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: dmaData,
          color: layer.DMAColor || '#F44534'
        }, {
          data: amaData,
          color: layer.AMAColor || '#45F445'
        }],
        thresholds: [],
        base: 0,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = dmaData.length + shift;
        }
        return [{
          label: `DMA`,
          value: dmaData[shift]
        }, {
          label: `DMAMA(${smooth})`,
          value: amaData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    dmi(layer, data, start, end) {
      const { N = 12 } = layer.params;
      const close = [],
            low = [],
            high = [];
      let dataStart = start - N - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length - 1) {
        end = data.length - 1;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
        high.push(data[i].high);
        low.push(data[i].low);
      }
      const { PosDI, NegDI, ADX } = dmi(high, low, close, N);
      let dataLen = end - start + 1;
      let PosDIData = [],
          NegDIData = [],
          ADXData = [];
      for (let i = PosDI.length - dataLen; i < PosDI.length; i++) {
        PosDIData.push(PosDI[i]);
        NegDIData.push(NegDI[i]);
        ADXData.push(ADX[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: PosDIData,
          color: layer.PosDIColor || '#F44534'
        }, {
          data: NegDIData,
          color: layer.NegDIColor || '#45F445'
        }, {
          data: ADXData,
          color: layer.AdxColor || '#FFFFFF'
        }],
        thresholds: [20, 80],
        base: 50,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = PosDIData.length + shift;
        }
        return [{
          label: `PosDI`,
          value: PosDIData[shift]
        }, {
          label: 'NegDI',
          value: NegDIData[shift]
        }, {
          label: 'ADX',
          value: ADXData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    dpo(layer, data, start, end) {
      const { N = 12 } = layer.params;
      const close = [];
      let dataStart = start - N - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
      }
      const dpoArray = dpo(close, N);
      const dataLen = end - start + 1;
      const dpoData = [];
      for(let i = dpoArray.length - dataLen; i < dpoArray.length; i++) {
        dpoData.push(dpoArray[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: dpoData,
          color: layer.DpoColor || '#F44534'
        }],
        thresholds: [-50, 50],
        base: 0,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = dpoData.length + shift;
        }
        return [{
          label: `DPO(${N})`,
          value: dpoData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    emv(layer, data, start, end) {
      const { N = 12, M = 6 } = layer.params;
      const volume = [],
          low = [],
          high = [];
      let dataStart = start - N - M - 1;
      if (dataStart < 0) {
        dataStart = 0;
      }

      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        volume.push(data[i].volume);
        high.push(data[i].high);
        low.push(data[i].low);
      }
      const { EMVValue, MAEMVVAlue } = emv(high, low, volume, N, M);
      let dataLen = end - start + 1;
      let EMVValueData = [],
          MAEMVVAlueData = [];
      for (let i = EMVValue.length - dataLen; i < EMVValue.length; i++) {
        EMVValueData.push(EMVValue[i]);
        MAEMVVAlueData.push(MAEMVVAlue[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: EMVValueData,
          color: layer.EmvColor || '#F44534'
        }, {
          data: MAEMVVAlueData,
          color: layer.MaEmv || '#45F445'
        }],
        thresholds: [],
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = EMVValue.length + shift;
        }
        return [{
          label: `Emv`,
          value: EMVValueData[shift]
        }, {
          label: 'MaEmv',
          value: MAEMVVAlueData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    fi(layer, data, start, end) {
      const volume = [],
          close = [];
      const dataStart = 0;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        volume.push(data[i].volume);
        close.push(data[i].close);
      }
      const fiValue = forceIndex(close, volume);
      let dataLen = end - start + 1;
      let FIData = [];
      for (let i = fiValue.length - dataLen; i < fiValue.length; i++) {
        FIData.push(fiValue[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: FIData,
          color: layer.FIColor || '#F44534'
        }],
        thresholds: [],
        base: 0,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = FIData.length + shift;
        }
        return [{
          label: `FI`,
          value: FIData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    mfi(layer, data, start, end) {
      const { N = 24 } = layer.params;
      const volume = [],
          high = [],
          low = [],
          close = [];
      let dataStart = start - N - 1;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        volume.push(data[i].volume);
        close.push(data[i].close);
        high.push(data[i].high);
        low.push(data[i].low);
      }
      const MFIValue = mfi(high, low, close, volume, N);
      let dataLen = end - start + 1;
      let MFIData = [];
      for (let i = MFIValue.length - dataLen; i < MFIValue.length; i++) {
        MFIData.push(MFIValue[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: MFIData,
          color: layer.MFIColor || '#F44534'
        }],
        thresholds: [20, 80],
        base: 50,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = FIData.length + shift;
        }
        return [{
          label: `MFI`,
          value: MFIData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    mtm(layer, data, start, end) {
      const { N = 24, M = 6 } = layer.params;
      const close = [];
      let dataStart = start - N - 1;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
      }
      const MTMValue = mtm(close, N);
      const MTMMAValue = ma(MTMValue, M);
      let dataLen = end - start - 1;
      let MTMData = [];
      let MTMMAData = [];
      for (let i = MTMValue.length - dataLen; i < MTMValue.length; i++) {
        MTMData.push(MTMValue[i]);
        MTMMAData.push(MTMMAValue[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: MTMData,
          color: layer.MTMColor || '#F44534'
        }, {
          data: MTMMAData,
          color: layer.MTMMAColor || '#56F644'
        }],
        thresholds: [],
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = MTMData.length + shift;
        }
        return [{
          label: `MTM`,
          value: MTMData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    nvi(layer, data, start, end) {
      const { N = 24 } = layer.params;
      const close = [],
        volume = [];
      let dataStart = 0;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
        volume.push(data[i].volume);
      }
      const NVIValue = nvi(close, volume);
      const MaNVI = ma(NVIValue, N);
      let dataLen = end - start + 1;
      let NviData = [];
      let MaNVIData = [];
      for (let i = NVIValue.length - dataLen; i < NVIValue.length; i++) {
        NviData.push(NVIValue[i]);
        MaNVIData.push(MaNVI[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: NviData,
          color: layer.NVIColor || '#44D534'
        }, {
          data: MaNVIData,
          color: layer.MANVIColor || '#F44534'
        }],
        thresholds: [],

        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = NviData.length + shift;
        }
        return [{
          label: `NVI`,
          value: NviData[shift]
        }, {
          label: 'MaNVI',
          value: MaNVIData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    obv(layer, data, start, end) {
      const { N = 24 } = layer.params;
      const close = [],
          volume = [];
      let dataStart = 0;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
        volume.push(data[i].volume);
      }
      const OBVValue = obv(close, volume);
      const MaOBValue = ma(OBVValue, N);
      let dataLen = end - start + 1;
      let ObvData = [],
        MaObvData = [];
      for (let i = OBVValue.length - dataLen; i < OBVValue.length; i++) {
        ObvData.push(OBVValue[i]);
        MaObvData.push(MaOBValue[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: ObvData,
          color: layer.OBVColor || '#44D534'
        }, {
          data: MaObvData,
          color: layer.MAOBVColor || '#F44534'
        }],
        thresholds: [],
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = ObvData.length + shift;
        }
        return [{
          label: `Obv`,
          value: ObvData[shift]
        }, {
          label: 'MaObv',
          value: MaObvData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    psy(layer, data, start, end) {
      const { N = 12, M = 6 } = layer.params;
      const close = [];
      let dataStart = start - N - M - 1;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
      }
      const psyValue = psy(close, N);
      const psyMa = ma(psyValue, M);
      let dataLen = end - start + 1;
      let psyData = [],
          psyMaData = [];
      for (let i = psyValue.length - dataLen; i < psyValue.length; i++) {
        psyData.push(psyValue[i]);
        psyMaData.push(psyMa[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: psyData,
          color: layer.PSYColor || '#44D534'
        }, {
          data: psyMaData,
          color: layer.MAPSYColor || '#F44534'
        }],
        thresholds: [25, 75],
        base: 50,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = psyData.length + shift;
        }
        return [{
          label: `PSY`,
          value: psyData[shift]
        }, {
          label: 'MaPSY',
          value: psyMaData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    pvi(layer, data, start, end) {
      const { N = 24 } = layer.params;
      const close = [],
          volume = [];
      let dataStart = 0;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
        volume.push(data[i].volume);
      }
      const PVIValue = pvi(close, volume);
      const MaPVI = ma(PVIValue, N);
      let dataLen = end - start + 1;
      let PviData = [];
      let MaPVIData = [];
      for (let i = PVIValue.length - dataLen; i < PVIValue.length; i++) {
        PviData.push(PVIValue[i]);
        MaPVIData.push(MaPVI[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: PviData,
          color: layer.PVIColor || '#44D534'
        }, {
          data: MaPVIData,
          color: layer.MAPVIColor || '#F44534'
        }],
        thresholds: [],
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = PviData.length + shift;
        }
        return [{
          label: `PVI`,
          value: PviData[shift]
        }, {
          label: 'MaPVI',
          value: MaPVIData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    roc(layer, data, start, end) {
      const { N = 12, M = 6 } = layer.params;
      const close = [];
      let dataStart = start - N - M - 1;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
      }
      const ROCValue = roc(close, N);
      const ROCMa = ma(ROCValue, M);
      let dataLen = end - start + 1;
      let ROCData = [],
          ROCMaData = [];
      for (let i = ROCValue.length - dataLen; i < ROCValue.length; i++) {
        ROCData.push(ROCValue[i]);
        ROCMaData.push(ROCMa[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: ROCData,
          color: layer.ROCColor || '#44D534'
        }, {
          data: ROCMaData,
          color: layer.MAROCColor || '#F44534'
        }],
        thresholds: [],
        base: 0,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = ROCData.length + shift;
        }
        return [{
          label: `ROC`,
          value: ROCData[shift]
        }, {
          label: 'MaROC',
          value: ROCMaData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    rvi(layer, data, start, end) {
      const { N = 12, M = 6 } = layer.params;
      const close = [];
      let dataStart = start - N - M - 1;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
      }
      const RVIValue = rvi(close, M, N);
      let dataLen = end - start + 1;
      let RVIData = [];
      for (let i = RVIValue.length - dataLen; i < RVIValue.length; i++) {
        RVIData.push(RVIValue[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: RVIData,
          color: layer.RVIData || '#44D534'
        }],
        thresholds: [],
        base: 0,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = RVIData.length + shift;
        }
        return [{
          label: `RVI`,
          value: RVIData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    vhf(layer, data, start, end) {
      const { N = 12, M = 6 } = layer.params;
      const close = [];
      let dataStart = start - N - M - 1;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
      }
      const VHFValue = vhf(close, M, N);
      let dataLen = end - start + 1;
      let VHFData = [];
      for (let i = VHFValue.length - dataLen; i < VHFValue.length; i++) {
        VHFData.push(VHFValue[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: VHFData,
          color: layer.VHFColor || '#44D534'
        }],
        thresholds: [],
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = VHFData.length + shift;
        }
        return [{
          label: `VHF`,
          value: VHFData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    vr(layer, data, start, end) {
      const { N = 12, M = 6 } = layer.params;
      const close = [], volume = [];
      let dataStart = start - N - M - 1;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
        volume.push(data[i].volume);
      }
      const VRValue = vr(close, volume, N);
      let dataLen = end - start + 1;
      let VRData = [];
      for (let i = VRValue.length - dataLen; i < VRValue.length; i++) {
        VRData.push(VRValue[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: VRData,
          color: layer.VRColor || '#44D534'
        }],
        thresholds: [40, 70, 150, 350],
        base: 200,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = VRData.length + shift;
        }
        return [{
          label: `VR`,
          value: VRData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    wad(layer, data, start, end) {
      const close = [], high = [], low = [];
      let dataStart = 0;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
        low.push(data[i].low);
        high.push(data[i].high)
      }
      const wadValue = wad(high, low, close);
      let dataLen = end - start + 1;
      let WadData = [];
      for (let i = wadValue.length - dataLen; i < wadValue.length; i++) {
        WadData.push(wadValue[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: WadData,
          color: layer.WADColor || '#44D534'
        }],
        thresholds: [],
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = WadData.length + shift;
        }
        return [{
          label: `WAD`,
          value: WadData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    wms(layer, data, start, end) {
      const { N = 20 } = layer.params;
      const close = [], high = [], low = [];
      let dataStart = 0;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
        low.push(data[i].low);
        high.push(data[i].high)
      }
      const wmsValue = wms(high, low, close, N);
      let dataLen = end - start + 1;
      let wmsData = [];
      for (let i = wmsValue.length - dataLen; i < wmsValue.length; i++) {
        wmsData.push(wmsValue[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: wmsData,
          color: layer.WMSColor || '#44D534'
        }],
        thresholds: [20, 80],
        base: 50,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = wmsData.length + shift;
        }
        return [{
          label: `WMS`,
          value: wmsData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    },
    wvad(layer, data, start, end) {
      const { N = 20 } = layer.params;
      const close = [], high = [], low = [], open = [], volume = [];
      let dataStart = 0;
      if (end > data.length) {
        end = data.length;
      }
      for (let i = dataStart; i < end; i++) {
        close.push(data[i].close);
        low.push(data[i].low);
        high.push(data[i].high);
        open.push(data[i].open);
        volume.push(data[i].volume);
      }
      const wvadValue = wvad(open, high, low, close, volume, N);
      let dataLen = end - start + 1;
      let wvadData = [];
      for (let i = wvadValue.length - dataLen; i < wvadValue.length; i++) {
        wvadData.push(wvadValue[i]);
      }
      layer.quoteLayer = new SymmetryLayer(layer.canvas, {
        width: layer.width,
        height: layer.height,
        data: [{
          data: wvadData,
          color: layer.WVADColor || '#44D534'
        }],
        thresholds: [],
        base: 0,
        xStep: layer.xStep,
        color: layer.color
      });
      layer.quoteLayer.make();
      layer.setLegendCallback((shift) => {
        if (shift < 0) {
          shift = wvadData.length + shift;
        }
        return [{
          label: `WVAD`,
          value: wvadData[shift]
        }];
      });
      layer.addChild(layer.quoteLayer);
    }

  };
  if (data.length === 0) {
    return;
  }
  if (funcs[layer.name]) {
    funcs[layer.name](layer, data,start, end);
  }
}

export default class QuoteLayer extends BaseLayer {
  constructor(canvas, options) {
    super(canvas);
    this.width = options.width || canvas.width;
    this.height = options.height || canvas.height;
    this.data = options.data || [];
    this.dataStart = options.dataStart || 0;
    this.dataEnd = options.dataEnd || this.data.length;
    this.name = options.name || 'macd';
    this.params = options.params || {};
    this.xStep = options.xStep || 1;
    this.quoteCaculator = options.quoteCaculator || defaultQuoteCaculator;
  }

  setLegendCallback(legendCall) {
    this.legendCallback = legendCall;
  }

  getLegend(shift) {
    if (this.legendCallback) {
      return this.legendCallback(shift);
    }
    return null;
  }

  make() {
    this.childs.splice(0, this.childs.length);
    this.quoteCaculator(this, this.data, this.dataStart, this.dataEnd);
  }
  containsPoint (point) {
    return point.x >= this.position.x
    && point.x <= this.position.x + this.width
    && point.y >= this.position.y
    && point.y <= this.position.y + this.height
  }
}
